package io.lvdaxian.mybatis12.builder;

import io.lvdaxian.mybatis12.mapping.*;
import io.lvdaxian.mybatis12.scripting.LanguageDriver;
import io.lvdaxian.mybatis12.session.Configuration;

import java.util.ArrayList;
import java.util.List;

/**
 * 映射构建器助手，建造者
 *
 * @author lihh
 */
public class MapperBuilderAssistant extends BaseBuilder {
  
  private String resource;
  private String currentNamespace;
  
  public MapperBuilderAssistant(Configuration configuration, String resource) {
    super(configuration);
  }
  
  public String getCurrentNamespace() {
    return currentNamespace;
  }
  
  public void setCurrentNamespace(String currentNamespace) {
    this.currentNamespace = currentNamespace;
  }
  
  public String applyCurrentNamespace(String base, boolean isReference) {
    if (base == null) {
      return null;
    }
    
    if (isReference) {
      if (base.contains(".")) return base;
    } else {
      if (base.startsWith(currentNamespace + ".")) {
        return base;
      }
      if (base.contains(".")) {
        throw new RuntimeException("Dots are not allowed in element names, please remove it from " + base);
      }
    }
    return currentNamespace + "." + base;
  }
  
  /**
   * 添加映射器语句
   *
   * @author lihh
   */
  public MappedStatement addMappedStatement(String id, SqlSource sqlSource, SqlCommandType sqlCommandType, Class<?> parameterType, String resultMap, Class<?> resultType, LanguageDriver lang) {
    // 给id加上namespace前缀：cn.bugstack.mybatis.test.dao.IUserDao.queryUserInfoById
    id = applyCurrentNamespace(id, false);
    MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlCommandType, sqlSource, resultType);
    
    // 结果映射，给 MappedStatement#resultMaps
    setStatementResultMap(resultMap, resultType, statementBuilder);
    
    MappedStatement statement = statementBuilder.build();
    // 映射语句信息，建造完存放到配置项中
    configuration.addMappedStatement(statement);
    
    return statement;
  }
  
  /**
   * 设置 statement 结果集合
   *
   * @param resultMap        结果 map
   * @param resultType       结果类型
   * @param statementBuilder statement 语句
   * @author lihh
   */
  private void setStatementResultMap(String resultMap, Class<?> resultType, MappedStatement.Builder statementBuilder) {
    // 因为暂时还没有在 Mapper XML 中配置 Map 返回结果，所以这里返回的是 null
    resultMap = applyCurrentNamespace(resultMap, true);
    
    List<ResultMap> resultMaps = new ArrayList<>();
    
    // 这里是尝试 优先处理 resultMap
    if (null != resultMap) {
      String[] resultMapNames = resultMap.split(",");
      for (String resultMapName : resultMapNames) {
        resultMaps.add(configuration.getResultMap(resultMapName.trim()));
      }
      
      
      /*
       * 通常使用 resultType 即可满足大部分场景
       * <select id="queryUserInfoById" resultType="cn.bugstack.mybatis.test.po.User">
       * 使用 resultType 的情况下，Mybatis 会自动创建一个 ResultMap，基于属性名称映射列到 JavaBean 的属性上。
       *
       * 这里的情况是：一个片段 就会生成 一个resultMap
       */
    } else if (null != resultType) {
      ResultMap.Builder inlineResultMapBuilder = new ResultMap.Builder(configuration, statementBuilder.id() + "-Inline", resultType, new ArrayList<>());
      resultMaps.add(inlineResultMapBuilder.build());
    }
    statementBuilder.resultMaps(resultMaps);
  }
  
  public ResultMap addResultMap(String id, Class<?> type, List<ResultMapping> resultMappings) {
    ResultMap.Builder inlineResultMapBuilder = new ResultMap.Builder(
        configuration,
        id,
        type,
        resultMappings);
    
    ResultMap resultMap = inlineResultMapBuilder.build();
    configuration.addResultMap(resultMap);
    return resultMap;
  }
}
